﻿using AutoUpdaterDotNET;
using DocsByReflection;
using DotLiquid;
using IniParser.Model;
using IniParser;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations.Schema;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Forms;
using OpenFileDialog = Microsoft.Win32.OpenFileDialog;
using System.Runtime.Loader;

namespace CodeSmithWpf;

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : HandyControl.Controls.Window, INotifyPropertyChanged
{
    private readonly CodeGenerateService service;

    public event PropertyChangedEventHandler PropertyChanged;

    public MainWindow(CodeGenerateService helloWorldService)
    {
        service = helloWorldService;
        InitializeComponent();
        this.DataContext = this;
        //this.LoadTypes();

        loadConfig();
    }

    private ObservableCollection<TypeDTO> listTypeVar = new ObservableCollection<TypeDTO>();
    public ObservableCollection<TypeDTO> listType
    {
        get
        {
            return this.listTypeVar;
        }
        set
        {
            this.listTypeVar = value;
            if(PropertyChanged != null)
            {
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs("listType"));
            }
        }
    }
  
    private void btnBrower_Click(object sender, RoutedEventArgs e)
    {
        if (string.IsNullOrWhiteSpace(this.txtCompanyName.Text))
        {
            HandyControl.Controls.MessageBox.Show("请填写公司名称", "提示");
            return;
        }
        OpenFileDialog ofg = new OpenFileDialog();
        ofg.Filter = "动态库 (*.dll)|*.dll;*.dll";
        ofg.RestoreDirectory = true;
        if (ofg.ShowDialog() == true)
        {
            this.txtSelectDllPath.Text = ofg.FileName;

           
        }
        saveConfig();
    }

    List<Type> BaseTypes = new List<Type>()
    {
        typeof(string),
        typeof(DateTime),
        typeof(char),
        typeof(byte),
        typeof(short),
        typeof(long),
        typeof(int),
        typeof(sbyte),
        typeof(Guid),
        typeof(float),
        typeof(double),
        typeof(decimal),
        typeof(bool),
        typeof(Single),
        typeof(uint),
        typeof(ushort),
        typeof(ulong),
        typeof(List<string>),
    };

    private List<TypeDTO> sourceList = new List<TypeDTO>();
    private void LoadTypes()
    {
        if (string.IsNullOrWhiteSpace(this.txtSelectDllPath.Text))
        {
            return;
        }
        if (!System.IO.File.Exists(this.txtSelectDllPath.Text))
        {
            return;
        }
        //listType.Clear();
        var dirPath = Path.GetDirectoryName(this.txtSelectDllPath.Text);
        var dir = new DirectoryInfo(dirPath);
        var domain = new AssemblyLoadContext("DomainServer", true);
        foreach (var item in dir.GetFiles("*.dll"))
        {
            if (item.FullName != this.txtSelectDllPath.Text)
            {
                try
                {
                   // Assembly.LoadFrom(item.FullName);
                    domain.LoadFromAssemblyPath(item.FullName);
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine(ex.Message);
                }
            }
        }
        //var assembly = Assembly.LoadFile(this.txtSelectDllPath.Text);
       var assembly= domain.LoadFromAssemblyPath(this.txtSelectDllPath.Text);
        var types =assembly.GetTypes();
        types = types.Where(x =>!string.IsNullOrWhiteSpace(x.FullName) &&IsEntity(x))
            .OrderBy(x=>GetTableName(x))
            .ToArray();
        if (!string.IsNullOrWhiteSpace(this.txtCompanyName.Text))
        {
            types = types.Where(x => x.FullName.StartsWith(this.txtCompanyName.Text + ".")).ToArray();
        }
       // var types = assembly.GetTypes().Where(x => x.BaseType.FullName== "Volo.Abp.Domain.Entities.IEntity").OrderBy(x => x.Name);
        foreach (var type in types)
        {

            var typeDoc = DocsService.GetXmlFromType(type,false);
            var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty | BindingFlags.DeclaredOnly);
            string typeDescription = type.Name;
            if (typeDoc != null)
            {
                typeDescription = typeDoc.SelectSingleNode("summary").InnerText;
                typeDescription = GetDescription(typeDescription);
            }
            TypeDTO typeDTO = new TypeDTO()
            {
                ClassDescription = typeDescription,
                ClassType = type,
                Checked = false,
                ClassName = type.Name,
                ClassFullName = type.FullName,
                CodeClassName=GetClassName(type),
                TableName  = GetTableName(type),
            };
            foreach (var property in properties)
            {
                if (property.IsDefined(typeof(ForeignKeyAttribute))|| property.IsDefined(typeof(NotMappedAttribute)))
                {
                    continue;
                }
                var propertyDoc = DocsService.GetXmlFromMember(property,false);
                string propertyDescription = property.Name;
                if (propertyDoc != null)
                {
                    propertyDescription = propertyDoc.SelectSingleNode("summary").InnerText;
                    propertyDescription = GetDescription(propertyDescription);
                }
              
                typeDTO.Properties.Add(new PropertyDTO()
                {
                    Property = property,
                    PropertyDescription = propertyDescription
                });
            }

            listTypeVar.Add(typeDTO);
            sourceList.Add(typeDTO);
        }
        //this.dtTable.ItemsSource = listType;
        
    }

    private string GetDescription(string description)
    {
        if (description.IsNullOrWhiteSpace())
        {
            return description;
        }
        return description.Replace("\r", "").Replace("\n", "").Replace(" ", "");
    }

    private void btnBrower2_Click(object sender, RoutedEventArgs e)
    {
        FolderBrowserDialog ofg = new FolderBrowserDialog();
        if (ofg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
        {
            this.txtGeneratePath.Text = ofg.SelectedPath;
        }
        saveConfig();
    }

    private void btnGenerate_Click(object sender, RoutedEventArgs e)
    {
        var list = listTypeVar.Where(x => x.Checked).ToList();
        if(list.Count == 0)
        {
            return;
        }
        list.ForEach(item =>
        {
            item.GeneratePath = this.txtGeneratePath.Text;
            item.ModuleName = this.txtModuleName.Text;
            item.ProjectName = this.txtProjectName.Text;
            item.CompanyName = this.txtCompanyName.Text;
            this.service.Generate(item);
        });
        this.txtTabs.SelectedIndex = 1;
        string code = this.service.GenerateSummary(this.txtProjectName.Text, this.txtModuleName.Text, list);
        this.txtCode.Text = code;

    }

    private void btnUpdater_Click(object sender, RoutedEventArgs e)
    {
        AutoUpdater.Start("http://42.192.143.58:8900/server.xml");
    }

    public bool IsEntity(Type type)
    {
        if (type.IsEnum)
        {
            return false;
        }
        var mostBaseType = GetMostBaseType(type);
        //{Name = "Entity" FullName = "Volo.Abp.Domain.Entities.Entity"}
        if (mostBaseType.FullName == "Volo.Abp.Domain.Entities.Entity")
        {
            return true;
        }
        return false;
    }


    private Type GetMostBaseType(Type type)
    {
        if (type.BaseType == null||type.BaseType.FullName=="System.Object")
        {
            return type;
        }
        return GetMostBaseType(type.BaseType);
    }

    public string GetTableName(Type type)
    {
        if (type.IsDefined(typeof(TableAttribute), false))
        {
          var tableAttribute =  type.GetCustomAttribute<TableAttribute>();
            return tableAttribute.Name;
        }
        return type.Name;
    }

    public string GetClassName(Type type)
    {
        if (type.Name.EndsWith("Entity"))
        {
            return type.Name.Substring(0, type.Name.Length - 6);
        }
        return type.Name;
    }

    private void txtKeywords_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
    {
        search();
    }

    private void search()
    {
        string keyword = txtKeywords.Text.Trim();
        listTypeVar.Clear();
        var searchResult = sourceList.Where(x => x.ClassDescription.Contains(keyword) || x.TableName.Contains(keyword)).ToList();
        foreach (var item in searchResult)
        {
            listTypeVar.Add(item);
        }
    }

    FileIniDataParser parser = new FileIniDataParser();
    IniData iniData = null;
    public void loadConfig()
    {
        if (!File.Exists("configuration.ini"))
        {
            iniData = new IniData();
            saveConfig();
        }
        iniData = parser.ReadFile("configuration.ini");
        this.txtCompanyName.Text = iniData.Sections["common"]["company_name"];
        this.txtProjectName.Text = iniData.Sections["common"]["project_name"];
        this.txtModuleName.Text = iniData.Sections["common"]["module_name"];
        this.txtSelectDllPath.Text = iniData.Sections["common"]["select_dll_path"];
        this.txtGeneratePath.Text = iniData.Sections["common"]["generate_path"];
    }

    public void saveConfig()
    {
        iniData["common"]["company_name"] = this.txtCompanyName.Text;
        iniData["common"]["project_name"] = this.txtProjectName.Text;
        iniData["common"]["module_name"] = this.txtModuleName.Text;
        iniData["common"]["select_dll_path"] = this.txtSelectDllPath.Text;
        iniData["common"]["generate_path"] = this.txtGeneratePath.Text;
        parser.WriteFile("configuration.ini", iniData);
    }

    private void btnSaveConfiguration_Click(object sender, RoutedEventArgs e)
    {
        saveConfig();
    }

    private void btnSearch_Click(object sender, RoutedEventArgs e)
    {
        search();
    }

    private void btnLoadTypes_Click(object sender, RoutedEventArgs e)
    {
        this.LoadTypes();
    }
}
